package com.lenovo.nova.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.AbsListView;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.lenovo.nova.util.Applications;
import com.lenovo.nova.util.debug.MyOldLog;
import com.lenovo.nova.util.debug.mylog;
import com.lenovo.nova.util.debug.slog;
import com.lenovo.nova.widget.ablistview.TwoWayAbsListView;
import com.lenovo.nova.widget.windowmanager.WindowManagerArrow;

@SuppressLint("NewApi")
public class VerticalArrowBuilderHelper implements View.OnClickListener {

    private boolean DEBUG = true;
	private static final String TAG = "HelperForAbsListViewArrow";
	private static int ARROW_OFFSET_FOR_GLOBAL = 0;
	private static int ARROW_OFFSET_FOR_NEW_GUI = 25;

	public static final int CLICK_ARROW_UP = 0;
	public static final int CLICK_ARROW_DOWN = 1;
	private boolean initialized = false;

	private int mTopArrowOffSet;
	private int mBottomArrowOffSet;

	private AbsListView mInstance;
	private String simpleName = null;
	private WindowManagerArrow arrow;
	private OnArrowClickListener mClick;
	private int mSmoothIndex;
	private int mItemAndDivideHeight;
	private int mOnePageShowItemCount;

    private int mScrollState = AbsListView.OnScrollListener.SCROLL_STATE_IDLE;

    public VerticalArrowBuilderHelper(AbsListView list) {
		mInstance = list;
		simpleName = list.getClass().getSimpleName();
		setTopArrowOffSet(ARROW_OFFSET_FOR_NEW_GUI);
        setBottomArrowOffSet(-ARROW_OFFSET_FOR_NEW_GUI);
	}

	public void onAttachedToWindow() {
		getViewTreeObserver().addOnGlobalLayoutListener(mInstance);
		arrow = new WindowManagerArrow(getContext(),false) {
			public void onClick(View v) {
				if (v == mTopView) {
					if (mClick != null) {
						mClick.onArrowClick(CLICK_ARROW_UP);
					}

				} else if (v == mBottomView) {
					if (mClick != null) {
						mClick.onArrowClick(CLICK_ARROW_DOWN);
					}
					arrow(CLICK_ARROW_DOWN);
				}
			}
		};
        arrow.setOnClickListener(this);

        arrow.setLeftVisible(false);
        arrow.setRightVisible(false);
		if (getAdapter() != null && getAdapter().getCount() <= 1) {
			setTwoArrowVisible(false);
		}
	}

	public void nextSmoothScroll() {
        if(mInstance instanceof ListView){
            int index = nextSmooth(mOnePageShowItemCount);
            mSmoothIndex = index;
        }else if (mInstance instanceof GridView){
            calcAndSmoothNext((GridView) mInstance,true);

        }
	}

    public void lastSmoothScroll() {
        if(mInstance instanceof  GridView){
            calcAndSmoothNext((GridView) mInstance, false);
        }else if(mInstance instanceof ListView){
            int index = lastSmooth(mOnePageShowItemCount);
            mSmoothIndex = index;
        }

    }

    public void smoothScrollBy(GridView gridView,int distance){
        gridView.smoothScrollBy(distance,500);
    }

    public WindowManagerArrow getArrowManager(){
        return arrow;
    }

    public void calcAndSmoothNext(GridView gridView,boolean down){
        int columns = gridView.getNumColumns();
        int onePageCount = gridView.getLastVisiblePosition() - gridView.getFirstVisiblePosition();
        mylog.i(TAG,"onePageCount " + onePageCount);
        int cow = onePageCount % columns == 0 ? onePageCount/columns : onePageCount/columns + 1;
        int itemHeight = gridView.getChildAt(0).getHeight();
        int minHeight = cow *  itemHeight + (cow -1 * gridView.getVerticalSpacing());
        int maxHeight = cow * (itemHeight + gridView.getVerticalSpacing());

        mylog.i(TAG,"GridView minHeight " + minHeight +
                    " maxHeight " + maxHeight +
                " currentHeight " + gridView.getHeight() +
                        " ItemViewY " + gridView.getChildAt(0).getY()
            );

        int direction = down ? 1 : -1;
        int distance = maxHeight * direction;
        smoothScrollBy(gridView,distance);
        mylog.i(TAG,"smooth distance " + distance);
    }

	public void onLayout(boolean changed, int l, int t, int r, int b) {
		int mViewHeight = b - t;

        if(DEBUG){
            mylog.d(TAG, "onLayout mViewHeight " + mViewHeight);
        }

		if (getChildAt(0) != null) {
			mItemAndDivideHeight = getChildAt(0).getHeight() + getDividerHeight();
            if(DEBUG){
                mylog.d(TAG, "onLayout mItemAndDivideHeight is " + mItemAndDivideHeight);
            }
		}

		if (mItemAndDivideHeight != 0 && mViewHeight % mItemAndDivideHeight == 0) {
			mOnePageShowItemCount = (mViewHeight / mItemAndDivideHeight);
		} else {
			if (mItemAndDivideHeight != 0) {
				mOnePageShowItemCount = (mViewHeight / mItemAndDivideHeight) + 1;
			}
		}

        if(DEBUG){
            mylog.d(TAG,"mViewHeight " + mViewHeight + " ");
        }

		mylog.d(TAG, simpleName + " mItemAndDivideHeight " + mItemAndDivideHeight + "  mOnePageShowItemCount " + mOnePageShowItemCount + "  getchildCount " + mInstance.getChildCount());
	}

    public void onGlobalLayout(boolean isVisibleToUser) {
        if(arrow != null){
            arrow.setBottomVisible(isVisibleToUser);
            arrow.setTopVisible(isVisibleToUser);
        }

        if(isVisibleToUser){
            refreshArrow();
        }

    }

	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

		int scrollY = mInstance.getScrollY();
		
		mylog.d(TAG, simpleName +
				"  onScroll firstVisibleItem " + firstVisibleItem + 
				"  visibleItemCount " + visibleItemCount + 
				"  totalItemCount " + totalItemCount + 
				"  scrollY " + scrollY );
		mSmoothIndex = firstVisibleItem;

//        initArrow();
//		refreshArrow();
	}

	public void onScrollChanged(int l, int t, int oldl, int oldt) {
//		System.out.println(simpleName + " onScrollChanged");
		//正常情况下，ListView滑动的时候会调用 onScroll ,onScrollChanged
				//但是如果是在Popwindown中，ListView可能不会调用 onScroll
				slog.p(TAG, simpleName +
						"  onScrollChanged l " + l +
						"  t " + t +
						"  oldl " + oldl +
						"  oldt " + oldt );
                if(mScrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
                    refreshArrow();
                }
	}

    public void onScrollStateChanged(AbsListView view, int scrollState) {
        mScrollState = scrollState;
        if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
            if(mInstance instanceof GridView){
                View firstView = getChildAt(0);
                int firstViewY = (int) firstView.getY();
                mylog.d(TAG,"firstView tag " + firstView.getTag() + " firstViewY " + firstViewY);
                if(firstViewY != 0){
//                    smoothScrollBy((GridView)mInstance,(int)-firstViewY);
//                    mInstance.smoothScrollToPosition(mSmoothIndex);
                    mInstance.smoothScrollToPositionFromTop(mSmoothIndex,0,1000);
                }
            }

            refreshArrow();

        }
    }

	/**
	 * 一般用不到，这个方法是在ListView或者GridView中，的Adapter的数据无效的时候调用,如下使用例子<br>
	 * adapter.registerDataSetObserver(new DataSetObserver() {
			@Override
			public void onChanged() {
				slog.p(TAG, TAG + " registerDataSetObserver onChanged " + getChildCount() + "   " + getCount());
			}

			@Override
			public void onInvalidated() {
				slog.p(TAG, TAG + " registerDataSetObserver onInvalidated " + getChildCount() + "   " + getCount());
				setTwoArrowVisible_(false);
			}
		});

	 */
	public void onInvalidated() {
		setTwoArrowVisible(false);
	}

    @Override
    public void onClick(View v) {
        switch ((Integer)v.getTag()){
            case WindowManagerArrow.ARROW_ID_TOP:
                arrow(CLICK_ARROW_UP);
                break;
            case WindowManagerArrow.ARROW_ID_BOTTOM:
                arrow(CLICK_ARROW_DOWN);
                break;
        }
    }

	@SuppressLint("MissingSuperCall")
	public void onDetachedFromWindow() {
		initialized = false;
		arrow.close();
	}

    public void setTopArrowDrawable(Drawable drawable){
        arrow.setTopDrawable(drawable);
    }

    public void setBottomArrowDrawable(Drawable drawable){
        arrow.setBottomDrawable(drawable);
    }

	public void notifyNeedInitArrow() {
		initialized = false;
	}

	public void arrow(int direction) {
		switch (direction) {
		case CLICK_ARROW_DOWN:
			nextSmoothScroll();
			break;
		case CLICK_ARROW_UP:
			lastSmoothScroll();
			break;
		default:
			break;
		}
	}

    public void setOnArrowClickListener(OnArrowClickListener l) {
        mClick = l;
    }

	public void setBottomArrowOffSet(int i) {
		mBottomArrowOffSet = i;
	}

	public void setTopArrowOffSet(int i) {
		mTopArrowOffSet = i;
	}

    private boolean isInTochMode() {
        return SettingsApplication.get().isInTouchMode();
    }

    private void setTwoArrowVisible(boolean visible) {
        if (arrow != null) {
            arrow.setTopVisible(visible);
            arrow.setBottomVisible(visible);
        } else {
            MyOldLog.e("arrow is null");
        }
        MyOldLog.p("setTwoArrowVisible_", MyOldLog.RANGE_LAST_METHOD);
    }

	private View getChildAt(int i) {
		return mInstance.getChildAt(i);
	}

	private int getDividerHeight() {
		if (mInstance instanceof ListView) {
			return ((ListView) mInstance).getDividerHeight();
		}
		return 0;
	}

	private int getFirstVisiblePosition() {
		return mInstance.getFirstVisiblePosition();
	}

	private int getLastVisiblePosition() {
		return mInstance.getLastVisiblePosition();
	}

	private int getCount() {
		return mInstance.getCount();
	}

	private int getHeight() {
		return mInstance.getHeight();
	}

	private int getPaddingBottom() {
		return mInstance.getPaddingBottom();
	}

	private int getPaddingTop() {
		return mInstance.getPaddingTop();
	}

	private ListAdapter getAdapter() {
		return mInstance.getAdapter();
	}

	private void getLocationOnScreen(int[] location) {
		mInstance.getLocationOnScreen(location);

	}

	private void getLocat3ionInWindow(int[] location) {
		mInstance.getLocationInWindow(location);
	}

	private ViewTreeObserver getViewTreeObserver() {
		// TODO Auto-generated method stub
		return mInstance.getViewTreeObserver();
	}

	private int getWindowVisibility() {
		// TODO Auto-generated method stub
		return mInstance.getWindowVisibility();
	}

	private void getDrawingRect(Rect outRect) {
		// TODO Auto-generated method stub
		mInstance.getDrawingRect(outRect);
	}

	private int getWidth() {
		// TODO Auto-generated method stub
		return mInstance.getWidth();
	}
	
	private void smoothScrollToPositionFromTop(int index, int i) {
		mInstance.smoothScrollToPositionFromTop(index, i);
		slog.p(TAG, "smoothScrollToPositionFromTop " + index + " " + i);
	}

	private void smoothScrollToPosition(int index){
		mInstance.smoothScrollToPosition(index);
		slog.p(TAG, "smoothScrollToPosition " + index);
	}

    private boolean isLastVisibleShow() {
        int lastVisiblePosition = getLastVisiblePosition();
        return lastVisiblePosition >= getCount() - 1;
    }

    @SuppressLint("NewApi")
    private boolean isFirstVisibleShow() {
        View firstChild = getChildAt(0);
        if (firstChild != null && (getFirstVisiblePosition() == 0)) {
            if (firstChild.getY() + firstChild.getHeight() - firstChild.getPaddingBottom() <= 0) {
                return false;
            }
        }
        return getFirstVisiblePosition() == 0;
    }

    private int calcTotalChildHeight() {
        slog.p(TAG, "calcTotalChildHeight " + getCount() + "  " + getDividerHeight());

        int mTotalChildHeight = 0;
        for (int i = 0; i < getCount(); i++) {
            if (getChildAt(0) != null) {
                mTotalChildHeight += getChildAt(0).getHeight();
            } else {
                MyOldLog.e("null");
            }
        }
        // add divider height
        mTotalChildHeight += getDividerHeight() * (getCount() - 1);
        return mTotalChildHeight;
    }

    private boolean isNeedShowArrow() {
        // height of all the item
        // add divider height
        int mTotalChildHeight = 0;
        mTotalChildHeight += getDividerHeight() * (getCount() - 1);
        mTotalChildHeight += getPaddingTop() + getPaddingBottom();

        int mRowContent = getCount();
        if(mInstance instanceof GridView){
            int temp = getCount() / ((GridView) mInstance).getNumColumns();
            mRowContent = getCount() % ((GridView) mInstance).getNumColumns() == 0 ? temp:temp+1;
        }

        for (int i = 0; i < mRowContent; i++) {
            if (getChildAt(0) != null) {
                mTotalChildHeight += getChildAt(0).getHeight();
                if(mTotalChildHeight > getHeight()){
                    return true;
                }
            } else {
                MyOldLog.e("null");
            }
        }

        mylog.d(TAG,"isNeedShowArrow mRowContent " + mRowContent +
                " mTotalChildHeight " + mTotalChildHeight +
                " getHeight() " + getHeight());

        return false;
    }

    private int nextSmooth(int step){
        int index = mSmoothIndex;
        index += step;

        if ((getAdapter() != null) && (index > getAdapter().getCount() - 1)) {
            // smoothScrollToPosition(index);
            index = getAdapter().getCount() - 1;
        }

        if(mInstance instanceof GridView && mSmoothIndex == 0){
            smoothScrollToPosition(index);
        }else{
            smoothScrollToPositionFromTop(index, 0);
        }

        slog.p(TAG,simpleName + "nextSmooth index " + index + " current smoothIndex " + mSmoothIndex);
        return index;
    }

    private int lastSmooth(int step){
        int index = mSmoothIndex;
        index -= step;

        if (index < 0) {
            index = 0;
        }
        // smoothScrollToPosition(index);
        smoothScrollToPositionFromTop(index, 0);
        slog.p(TAG,simpleName + "lastSmoothScroll index " + index + " current smoothIndex " + mSmoothIndex);
        return index;
    }

    /**
     * 该方法被调用一次就可以了，只是初始化上下箭头
     */
    private void initArrow() {
        if (arrow != null && !initialized) {
            initialized = true;
            boolean mCanFling = isNeedShowArrow();
            slog.p(TAG, "initArrow  childTotalHeightAndPadding: "  + " mCanFling is " + mCanFling);
            if (mCanFling && getWindowVisibility() == View.VISIBLE) {
                setShowBottomArrow();
            } else {
                setTwoArrowVisible(false);
            }

        } else {
            if (arrow == null) {
                MyOldLog.e("Error maybe arrow is null ");
            }
        }
    }

	private Context getContext(){
		return mInstance.getContext();
	}

    private void refreshArrow() {
        initArrow();

        if (getHeight() > 0 && getWindowVisibility() == View.VISIBLE) {
            // when the children height is less than the parent height,update
            // the arrow(set all arrows invisiable)
//            Rect outRect = new Rect();
//            getDrawingRect(outRect);
//            slog.p(TAG, "refreshArrow outRect " + outRect);

            boolean mCanFling = isNeedShowArrow();
            slog.p(TAG, "refreshArrow  mCanFling " + mCanFling +
                    "  isFirstVisibleShow() " + isFirstVisibleShow() +
                    "  mSmoothIndex " + mSmoothIndex +
                    "  isLastVisibleShow() "  + isLastVisibleShow());

            if (mCanFling && arrow != null) {
                if (isFirstVisibleShow() && mSmoothIndex == 0) {
                    setShowBottomArrow();
                } else if (isLastVisibleShow()) {
                    setShowTopArrow();
                } else {
                    setTwoArrowVisible(true);
                }
            } else {
                setTwoArrowVisible(false);
            }

            // 有时候ListView的高度需要跟随着变化，所以需要刷新箭头的额位置
            int[] location = new int[2];
            getLocationOnScreen(location);
//            int[] locationInWind = new int[2];
//            getLocationInWindow(locationInWind);

            int topY = location[1] - arrow.getTopImageViewHeight();
            mylog.d(TAG, "init arrow location is " + location[0] + "   " + location[1] + " arrow topY is " + topY + "\n ");

            int height = getHeight();
            int topViewY = topY - ARROW_OFFSET_FOR_GLOBAL + mTopArrowOffSet;
            int bottomY = location[1] + height + ARROW_OFFSET_FOR_GLOBAL + mBottomArrowOffSet;
            int imageX = location[0] + (getWidth() - arrow.getTopImageViewWidth()) / 2;

            arrow.showArrowYPosition(topViewY, bottomY);
            arrow.showArrowXPosition(imageX);
            mylog.d(TAG, "topViewY " + topViewY + "  bottomY " + bottomY + "  imageX  " + imageX);
        }

    }

    private void setShowTopArrow() {
        if (arrow != null) {
            arrow.setTopVisible(true);
            arrow.setBottomVisible(false);
        } else {
            MyOldLog.e("arrow is null");
        }
        if (Applications.isInDebugMode) {
            MyOldLog.p("setShowTopArrow", MyOldLog.RANGE_LAST_METHOD);
        }
    }

    private void setShowBottomArrow() {
        if (arrow != null) {
            arrow.setTopVisible(false);
            arrow.setBottomVisible(true);
        } else {
            MyOldLog.e("arrow is null");
        }
        MyOldLog.p("setShowBottomArrow", MyOldLog.RANGE_LAST_METHOD);
    }

    public interface OnArrowClickListener {
        void onArrowClick(int flag);
    }
}
